/* -*- c -*- */

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <sobjc-commons/defines.h>
#include <sobjc-commons/str_list.h>
#include <sobjc-commons/utils.h>
#include "command.h"

static BOOL no_inline_cache     = NO;
static BOOL no_dispatch_table   = NO;

#define LG_MALLOC       objc_malloc
#define LG_REALLOC      objc_realloc
#define LG_FREE         objc_free
%}

%program    "sobjc"
%usage      "[options] file ..."
%version    "Strong Objective-C Compiler 0.4"

%%

-v, --verbose:
  help "Verbose mode"
{
  objc_main_opts.verbose = 1;
}

--cc-verbose:
  help "Verbose mode for compiler"
{
  objc_main_opts.cc_verbose = 1;
}

-g:
  help "Produces debugging information"
{
  objc_main_opts.debug = 1;
}

--profile:
  help "Profiles message sending"
{
  objc_main_opts.profile = 1;
}

--cc name:
  help "Specify compiler; gcc (default)",
  select "gcc"
{
  if (STREQ($name, "gcc"))
    objc_main_opts.cc = OBJC_CC_GCC;
}

-c:
  help "Exits after compiling or assembling without linking"
{
  objc_main_opts.does_link = 0;
}

-S:
  help "Exits after compiling without assembling"
{
  objc_main_opts.does_asm = 0;
  objc_main_opts.does_link = 0;
}

-t:
  help "Exits after translating without compiling"
{
  objc_main_opts.does_compile = 0;
  objc_main_opts.does_asm = 0;
  objc_main_opts.does_link = 0;
}

-E:
  help "Exits after preprocessing without translating and compiling"
{
  objc_main_opts.does_translate = 0;
  objc_main_opts.does_compile = 0;
  objc_main_opts.does_asm = 0;
  objc_main_opts.does_link = 0;
}

-o file:
  help "Output file name"
{
  objc_main_opts.output = objc_strdup($file);
}

-I path:
  help "Add path to head of the load path list",
{
  objc_str_list_add_set(&objc_main_opts.load_paths, $path);
}

-l name:
  help "Search library when linking"
{
  objc_str_list_add_set(&objc_main_opts.libs, $name);
}

-L path:
  help "Add path to the list of directories to be search for -l" 
{
  objc_str_list_add_set(&objc_main_opts.lib_paths, $path);
}

--save-temps:
  help "Do not delete intermediate files",
{
  objc_main_opts.saves_temps = 1;
}

--static:
  help "Links libraries statically"
{
  objc_main_opts.links_static = 1;
}

/*
--no-baustain:
  help "Do not links baustein (default standard library)"
{
  objc_main_opts.links_baustein = 0;
}
*/

-O level:
  type int,
  help "Optimizes compiled code (0-2)"
{
  objc_main_opts.optimize_lv = $level;
  if ($level >= 1 && !no_inline_cache)
    objc_main_opts.inline_cache = 1;
  if ($level >= 2 && !no_dispatch_table)
    objc_main_opts.dtable = 1;
}

-X arg:
  help "Pass arg on to the back-end compiler",
{
  objc_str_list_add_set(&objc_main_opts.compiler_opts, $arg);
}

-f arg:
  help "Flag control"
{
  if (STREQ($arg, "syntax-only"))
    objc_main_opts.syntax_only = 1;
  else
    objc_str_list_add_set(&objc_main_opts.flags, $arg);
}

--ansi:
  help "Supports all ISO C90 programs"
{
  objc_main_opts.ansi = 1;
}

--pedantic:
{
  objc_main_opts.w_pedantic = 1;
}

--pedantic-errors:
{
  objc_main_opts.pedantic_errors = 1;
}

-w:
{
  objc_main_opts.no_warn = 1;
}

-W arg:
  help "Warning control"
{
  if (STREQ($arg, "no-protocol"))
    objc_main_opts.w_no_protocol = 1;
  else if (STREQ($arg, "undeclared-selector"))
    objc_main_opts.w_undeclared_sel = 1;
  else if (STREQ($arg, "strict-selector-match"))
    objc_main_opts.w_strict_sel_match = 1;
  else
    objc_str_list_add_set(&objc_main_opts.warns, $arg);
}

/* Objective-C options */
--constant-string-class name:
  help "Name of the class to instantiate for each literal string",
{
  objc_main_opts.cstr_class = objc_strdup($name);
}

--no-nil-receivers:
  help "Allows using `nil' as receiver in all Objective-C message expressions",
{
  objc_main_opts.no_nil_recvs = 1;
}

/*
--gen-decls:
  help "Dumps interface declarations to file",
{
  objc_main_opts.gen_decls = 1;
}
*/

--inline-cache:
  help "Generates inline cache for message passing"
{
  objc_main_opts.inline_cache = 1;
}

--no-inline-cache:
  help "Do not generates inline cache for message passing"
{
  no_inline_cache = YES;
  objc_main_opts.inline_cache = 0;
}

--dispatch-table:
  help "Generates dispatch table for message passing"
{
  objc_main_opts.dtable = 1;
}

--no-dispatch-table:
  help "Do not generates dispatch table for message passing"
{
  no_dispatch_table = YES;
  objc_main_opts.dtable = 0;
}

--no-strict-message:
  help "Enables sending message not declared in receiver class"
{
  objc_main_opts.no_strict_msg = 1;
}

+ files ...:
{
  int i;

  objc_cmd = (char *)malloc(sizeof(char) * strlen(lg_cmd)+1);
  strcpy(objc_cmd, lg_cmd);

  objc_main_opts.nfiles = $nvargs;
  objc_main_opts.files = (char **)malloc(sizeof(char *) * $nvargs);
  for (i = 0; i < $nvargs; i++) {
    objc_main_opts.files[i] = (char *)malloc(sizeof(char) * strlen($files[i])+1);
    strcpy(objc_main_opts.files[i], $files[i]);
  }
}

%%

void
objc_parse_opts(int argc, char **argv)
{
  objc_main_opts.nargs = argc;
  objc_main_opts.args = argv;
  objc_main_opts.load_paths = NULL;
  objc_main_opts.libs = NULL;
  objc_main_opts.lib_paths = NULL;
  lg_parse(argc, argv);
}
